package com.hmdp.service.impl;

import com.hmdp.dto.Result;
import com.hmdp.entity.SeckillVoucher;
import com.hmdp.entity.VoucherOrder;
import com.hmdp.mapper.VoucherOrderMapper;
import com.hmdp.service.ISeckillVoucherService;
import com.hmdp.service.IVoucherOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.utils.RedisIdWorker;
import com.hmdp.utils.UserHolder;
import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 虎哥
 * @since 2021-12-22
 */
@Service
public class VoucherOrderServiceImpl extends ServiceImpl<VoucherOrderMapper, VoucherOrder> implements IVoucherOrderService {
    @Resource
    private ISeckillVoucherService seckillVoucherService;
    @Resource
    private RedisIdWorker redisIdWorker;

    /**
     * 抢购秒杀卷
     * @param voucherId
     * @return
     */
    @Override
    public Result seckillVoucher(Long voucherId) {
        //1. 查询优惠卷信息
        SeckillVoucher seckillVoucher = seckillVoucherService.getById(voucherId);


        //2. 判断秒杀是否开始
        if(seckillVoucher == null){
            return Result.fail("优惠券不存在");
        }
        if(seckillVoucher.getBeginTime().isAfter(LocalDateTime.now())){
            return Result.fail("秒杀尚未开始");
        }
        if(seckillVoucher.getEndTime().isBefore(LocalDateTime.now())){
            return Result.fail("秒杀已结束");
        }



        //3. 判断库存是否充足
        if(seckillVoucher.getStock() < 1){
            return Result.fail("库存不足");
        }


        //先上锁，事务提交后在释放锁，可以确保线程安全
        Long userId = UserHolder.getUser().getId();
        synchronized (userId.toString().intern()){
            //获取事务的代理对象，用代理对象去调用方法可以让spring管理事务，因为this是没有事务的，可能会出现事务失效的情况
            //return createVoucherOrder(voucherId);
            IVoucherOrderService proxy = (IVoucherOrderService) AopContext.currentProxy();
            return proxy.createVoucherOrder(voucherId);
        }

    }

    @Transactional//这里需要事务，因为要保证库存和订单同时成功或者失败
    public  Result createVoucherOrder(Long voucherId) {//这里不能在方法上加悲观锁，会导致所有对象都被锁住，性能过低
        //3.1 判断是否为同一个用户
        Long userId = UserHolder.getUser().getId();

        //不能在方法内上锁，因为释放锁以后，事务可能还没提交，其他的线程就进来重复执行逻辑，导致锁失效
//        synchronized (userId.toString().intern()){

        //3.2 查询是否购买过
        Integer count = query().eq("user_id", userId).eq("voucher_id", voucherId).count();
        if(count > 0){
            return Result.fail("该用户已经购买过");
        }

        //4. 扣减库存
        boolean success = seckillVoucherService.update()
                .setSql("stock = stock - 1")
                .eq("voucher_id", voucherId).gt("stock", 0)
                .update();


        //4.1 扣减失败
        if(!success){
            return Result.fail("库存不足");
        }

        //5. 创建订单
        VoucherOrder voucherOrder = new VoucherOrder();
        //5.1 订单ID
        Long orderId = redisIdWorker.nextId("order");
        voucherOrder.setId(orderId);
        //5.2 用户ID
        voucherOrder.setUserId(userId);
        //5.3 优惠券ID
        voucherOrder.setVoucherId(voucherId);
        //5.4 写入订单
        save(voucherOrder);

        //6. 返回订单ID
        return Result.ok(orderId);
//        }

    }
}
